// UCLA CS 111 Lab 1 command execution

#include "command.h"
#include "command-internals.h"
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


void run_child(command_t c);
int command_status (command_t c)
{
  return c->status;
}
void executeActualCommand(command_t c)
{
	//call execvp

	pid_t cpid, ppid;
	int child_status;
	//char *const cmd[] = {"cat", (char *) 0};
	/*if (c->input != NULL)
		freopen(c->input, "r", stdin);

	if (c->output != NULL)
		freopen(c->output, "w", stdout);
	execvp(cmd[0], cmd);
	fclose(stdin);
	fclose(stdout);*/
	cpid = fork();
	if(cpid == 0) {
	    //Have the child process execute command
		run_child(c);
	  }
	else if (cpid > 0) {
		do {
				ppid = wait(&child_status);
			} while (ppid != cpid);
		c->status = child_status;
	}
	return;
}
void run_child(command_t c)
{
	char** cmd = c->u.word;
	//check for input and output redirects
	if (c->input != NULL)
		freopen(c->input, "r", stdin);
	if (c->output != NULL)
		freopen(c->output, "w", stdout);

	//execute command
	execvp(cmd[0], cmd);
	// If execvp returns, it must have failed.
	error(1, 0, "error executing command");
	fclose(stdin);
	fclose(stdout);

}
void executeGeneric(command_t c)
{
	switch(c->type)
	{
		case AND_COMMAND:
			executeGeneric( c->u.command[0] );
			if(c->u.command[0]->status == 0)
			{
				executeGeneric( c->u.command[1] );
				c->status = c->u.command[1]->status;
			}
			else
				c->status = c->u.command[0]->status;
			break;
		case OR_COMMAND:
			executeGeneric( c->u.command[0] );
			if(c->u.command[0]->status != 0)
			{
				executeGeneric( c->u.command[1] );
				c->status = c->u.command[1]->status;
			}
			else
				c->status = c->u.command[0]->status;
			break;
		case SEQUENCE_COMMAND:
		case PIPE_COMMAND:
			if (c->u.command[0]->output == NULL)
			{
				c->u.command[0]->output = "temp";
				c->u.command[1]->input = "temp";
			}
			executeGeneric( c->u.command[0] );
			executeGeneric( c->u.command[1] );
			break;
		case SIMPLE_COMMAND:
			executeActualCommand(c);
			break;
		case SUBSHELL_COMMAND:
			if (c->input != NULL)
				c->u.subshell_command->input = c->input;
			if (c->output != NULL)
				c->u.subshell_command->output = c->output;
			executeGeneric(c->u.subshell_command);
			c->status = command_status(c->u.subshell_command);
			break;
	}
}
void execute_command (command_t c, int time_travel)
{
	executeGeneric(c);
}
